package cool.taomu.toolkit.kademlia.utils

import com.google.gson.reflect.TypeToken
import com.google.inject.Injector
import com.google.inject.Key
import com.google.inject.name.Names
import cool.taomu.toolkit.TaomuGuice
import cool.taomu.toolkit.entity.TaomuConfig
import java.lang.annotation.Annotation
import java.lang.reflect.Method
import java.util.ArrayList
import java.util.HashSet
import java.util.List
import java.util.Map
import java.util.Set
import javax.inject.Inject
import javax.inject.Named
import javax.ws.rs.DELETE
import javax.ws.rs.GET
import javax.ws.rs.POST
import javax.ws.rs.PUT
import javax.ws.rs.Path
import org.eclipse.xtend.lib.annotations.Accessors
import org.reflections.Reflections
import org.reflections.scanners.Scanners
import org.reflections.util.ConfigurationBuilder
import org.slf4j.LoggerFactory
import cool.taomu.toolkit.Context

@Accessors
class ResourceCollector {
	val static LOG = LoggerFactory.getLogger(ResourceCollector);

	var static HTTP_METHOD_ANNOTATIONS = #{GET -> "get", POST -> "post", PUT -> "put", DELETE -> "delete"}

	Set<String> scanResult = new HashSet();

	@Inject
	//@Named("kademlia.resource.injector")
	Context ginjector;

	def init() {
		var r = getScanPackages(ginjector.injectorSupplier.get);
		r.forEach [
			scanResult.addAll(scan(it));
		]
	}

	def getScanPackages(Injector injector) {
		LOG.info("binding : {}", injector.bindings);
		var pks = new ArrayList<String>();
		try {
			if (injector.getExistingBinding(Key.get(TaomuConfig, Names.named(TaomuGuice.JESERY_PACKAGES))) !== null) {
				var pk = injector.getInstance(Key.get(TaomuConfig, Names.named(TaomuGuice.JESERY_PACKAGES)));
				pks.addAll(pk.get(new TypeToken<List<String>>() {
				}));
			}
		} catch (Exception ex) {
			LOG.debug("packages Exception:{}", ex);
		}
		try {
			if (injector.getExistingBinding(Key.get(String, Names.named(TaomuGuice.JESERY_SERVICELOADER_PACKAGES))) !==
				null) {
				var String slpk = injector.getInstance(
					Key.get(String, Names.named(TaomuGuice.JESERY_SERVICELOADER_PACKAGES)));
				pks.add(slpk);
			}
		} catch (Exception ex) {
			LOG.debug("packages Exception:{}", ex);
		}
		LOG.info("packages:{}", pks);
		return pks
	}

	def scan(String basePackage) {
		var Reflections reflections = new Reflections(
			new ConfigurationBuilder().forPackages(basePackage).addScanners(Scanners.TypesAnnotated));
		var Set<Class<?>> resourceClasses = reflections.getTypesAnnotatedWith(Path);
		var result = new HashSet<String>();
		for (Class<?> clazz : resourceClasses) {
			var Path classPath = clazz.getAnnotation(Path);
			var String basePath = normalizePath(classPath.value());
			for (Method method : clazz.getDeclaredMethods()) {
				for (Map.Entry<Class<? extends Annotation>, String> entry : HTTP_METHOD_ANNOTATIONS.entrySet()) {
					if (method.isAnnotationPresent(entry.getKey())) {
						var String httpMethod = entry.getValue();
						var String methodPath = "";
						if (method.isAnnotationPresent(Path)) {
							methodPath = method.getAnnotation(Path).value().normalizePath;
						}
						var String fullPath = basePath.mergePaths(methodPath);
						// 格式：get:/users 或 post:/users/create
						result.add(httpMethod + ":" + fullPath);
					}
				}
			}
		}
		return result;
	}

	// 确保路径以 / 开头且不重复
	private def String normalizePath(String path) {
		if (path === null || path.isEmpty()) {
			return "";
		}
		return path.startsWith("/") ? path : "/" + path;
	}

	// 合并类路径和方法路径
	private def String mergePaths(String classPath, String methodPath) {
		if (classPath === null || classPath.isEmpty()) {
			return methodPath;
		}
		if (methodPath === null || methodPath.isEmpty()) {
			return classPath;
		}

		// 去掉两边多余的斜杠再合并
		var String cleanedClassPath = classPath.replaceAll("/+$", "");
		var String cleanedMethodPath = methodPath.replaceAll("^/+", "");

		return cleanedClassPath + (cleanedMethodPath.isEmpty() ? "" : "/" + cleanedMethodPath);
	}
}
